package com.zsl.swing.redis.desktop.window.list;

import com.zsl.swing.redis.desktop.common.Constants;
import com.zsl.swing.redis.desktop.model.NodeEntity;
import com.zsl.swing.redis.desktop.pool.ThreadPoolUtils;
import com.zsl.swing.redis.desktop.type.DbOptEnum;
import com.zsl.swing.redis.desktop.utils.*;
import com.zsl.swing.redis.desktop.window.ZslRedisDesktopMainWindow;
import com.zsl.swing.redis.desktop.window.panel.ZslValueShowPanel;
import redis.clients.jedis.params.ScanParams;
import redis.clients.jedis.resps.ScanResult;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ZslKeyList extends JList<ZslListNode> {

    private final NodeEntity dbEntity;

    private final ZslValueShowPanel valueShowPanel;

    public ZslKeyList(NodeEntity dbEntity, ZslValueShowPanel valueShowPanel){
        this.setModel(new ZslListModel<>());

        this.dbEntity = dbEntity;
        this.valueShowPanel = valueShowPanel;

        this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        this.addListSelectionListener(this::doForSelect);

    }

    private void doForSelect(ListSelectionEvent e) {
        ZslListNode selectedNode = this.getSelectedValue();

        if(Objects.isNull(selectedNode)){
            return ;
        }

        int dbIndex = this.dbEntity.getDbIndex();
        String uniqueId = this.dbEntity.getUniqueId();
        String redisKey = selectedNode.getRedisKey();

        if(DbOptEnum.MORE.getText().equals(redisKey)){
            this.removeOneElement(redisKey);
            this.queryLikeList(selectedNode.getRedisVal(), selectedNode.getCursor(), selectedNode.getScanCount(),false);
        }else{
            ZslRedisDesktopMainWindow.getZslLogPanel().log("开始查询 ----->");

            new SwingWorker<String,Long>(){

                @Override
                protected String doInBackground() {
                    long memoryUsageInByte = RedisUtils.memoryUsageInByte(uniqueId, dbIndex, redisKey);

                    return memoryUsageInByte <= ZslRedisDesktopMainWindow.getOtherGeneralConfig().getMemoryUsageLimit()?
                            RedisUtils.get(uniqueId, dbIndex, redisKey): Constants.REDIS_QUERY_TIMEOUT_UNIQUE_NAME;
                }

                @Override
                protected void done() {
                    try {
                        String result = get(5L, TimeUnit.SECONDS);
                        if(Constants.REDIS_QUERY_TIMEOUT_UNIQUE_NAME.equals(result)){
                            DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(), "当前key占用内存超出支持限制，请选择命令行窗口进行操作！");
                        }else{
                            ZslKeyList.this.valueShowPanel.setRedisValue(redisKey,result);
                        }
                    } catch (InterruptedException | TimeoutException | ExecutionException e) {
                        ZslRedisDesktopMainWindow.getZslLogPanel().logError(e);
                        DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(), "当前key占用内存超出支持限制，请选择命令行窗口进行操作！");
                    }

                    ZslRedisDesktopMainWindow.getZslLogPanel().log("查询完成----->");
                }
            }.execute();
        }


    }


    public void queryLikeList(String keyword, String cursor, int scanCount, boolean deleteOld) {

        if(deleteOld){
            this.removeAllElements();
            this.valueShowPanel.clearKeyValue();
        }


        ThreadPoolUtils.execute(() -> {

            long start = System.currentTimeMillis();


            int dbIndex = this.dbEntity.getDbIndex();
            String uniqueId = this.dbEntity.getUniqueId();
            ScanResult<String> scanResult = RedisUtils.scanResult(uniqueId, dbIndex, keyword, cursor, scanCount);

            System.out.println("[scan]命令耗时：" + (System.currentTimeMillis() - start) + "毫秒！");


            SwingUtilities.invokeLater(() -> {

                if(Objects.isNull(scanResult)){
                    ZslRedisDesktopMainWindow.getZslLogPanel().logError("查询失败！");
                    return;
                }

                List<String> keyList = scanResult.getResult();
                if(!CollectionUtils.isEmpty(keyList)){
                    this.addElementList(keyList);
                }

                String nextCursor = scanResult.getCursor();
                if(!ScanParams.SCAN_POINTER_START.equals(nextCursor)) {
                    this.addOneElement(DbOptEnum.MORE.getText(), keyword, nextCursor , scanCount);
                }
            });
        });
    }

    public void queryOne(String keyword) {
        this.removeAllElements();

        long start = System.currentTimeMillis();
        String redisValue = RedisUtils.get(this.dbEntity.getUniqueId(), this.dbEntity.getDbIndex(), keyword);
        ZslRedisDesktopMainWindow.getZslLogPanel().log("界面执行[get]命令耗时：" + (System.currentTimeMillis() - start) + "毫秒！");

        if(!StringUtils.isEmpty(redisValue)){
            this.addOneElement(keyword, redisValue);
            this.valueShowPanel.setRedisValue(keyword,redisValue);
        }

    }

    public void deleteOne(String keyword) {
        int dbIndex = this.dbEntity.getDbIndex();
        String uniqueId = this.dbEntity.getUniqueId();

        boolean flag = RedisUtils.existsKey(uniqueId,dbIndex,keyword);
        if(!flag){
            DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(),"key 不存在！");
            return;
        }

        boolean confirm = DialogUtils.confirmDialog(ZslRedisDesktopMainWindow.getMainWindow(), "确定要从Redis中删除 " + keyword + "?");
        if(!confirm){
            return;
        }

        long start = System.currentTimeMillis();
        boolean del = RedisUtils.unlinkKeyList(uniqueId, dbIndex, keyword);
        ZslRedisDesktopMainWindow.getZslLogPanel().log("界面执行[del]命令耗时：" + (System.currentTimeMillis() - start) + "毫秒！");
        if(!del){
            DialogUtils.errorDialog(ZslRedisDesktopMainWindow.getMainWindow(),"删除失败，请重试！");
        }else{
            this.removeOneElement(keyword);
            this.valueShowPanel.clearKeyValue(keyword);
        }
    }

    public void deleteLike(String keyword, int deleteLikeScanCount) {
        boolean confirm = DialogUtils.confirmDialog(ZslRedisDesktopMainWindow.getMainWindow(), "确定从Redis删除包含" + keyword + "的所有Key么？");
        if(confirm){

            String fileName = LongTimeTaskUtils.buildDeletedKeysFileNameFullPath(keyword,dbEntity.getUniqueId());

           ThreadPoolUtils.execute(() -> {
               boolean result = RedisUtils.scanAndDel(dbEntity.getUniqueId(), dbEntity.getDbIndex(), keyword, deleteLikeScanCount, fileName);

               SwingUtilities.invokeLater(() ->{
                   if(!result){
                       DialogUtils.errorDialog(ZslRedisDesktopMainWindow.getMainWindow(), "模糊删除" + keyword + "失败！");
                   }else{
                       this.removeAllElements();
                       this.valueShowPanel.clearKeyLike(keyword);

                       DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(), "已删除Keys  的文件名称：" + fileName);
                   }


                });

            });

        }
    }

    public synchronized void  removeOneElement(String keyword){
        ZslListNode node = new ZslListNode();
        node.setRedisKey(keyword);

        ZslListModel model = (ZslListModel) this.getModel();
        model.removeOneElement(node);
    }

    public synchronized void removeAllElements(){
        ZslListModel model = (ZslListModel) this.getModel();
        model.removeAllElementList();
    }

    public synchronized void addOneElement(String keyword, String redisValue){
        this.addOneElement(keyword, redisValue, null, 0);
    }

    public synchronized void addElementList(List<String> keyList){
        if(!CollectionUtils.isEmpty(keyList)){
            ZslListModel model = (ZslListModel) this.getModel();

            List<ZslListNode> nodeList = new ArrayList<>();
            for(String key: keyList){
                ZslListNode node = new ZslListNode();
                node.setRedisKey(key);

                nodeList.add(node);
            }

            model.addElementList(nodeList);
        }
    }

    public synchronized void addOneElement(String keyword, String redisValue, String cursor, int scanCount){
        if(!StringUtils.isEmpty(keyword)){
            ZslListModel model = (ZslListModel) this.getModel();

            ZslListNode node = new ZslListNode();
            node.setRedisKey(keyword);
            node.setRedisVal(redisValue);
            node.setCursor(cursor);
            node.setScanCount(scanCount);

            model.addOneElement(node);
        }

    }


    public NodeEntity getDbEntity(){
        return this.dbEntity;
    }
}
